#ifndef MODBUS_H
#define MODBUS_H

#include "user_global.h"
#include "device_usart.h"


//==========================================================
// RO_BIT
//==========================================================

typedef enum RO_BIT_INDEX
{
    S1_AT_HOME,                          // 0000 S1电机在原点. 1: 在原点 0: 不在原点
    S2_AT_HOME,                          // 0001 S2电机在原点. 1: 在原点 0: 不在原点
    V1_AT_HOME,                          // 0002 V1电机在原点. 1: 在原点; 0: 不在原点
    V2_AT_HOME,                          // 0003 V2电机在原点. 1: 在原点; 0: 不在原点
    V3_AT_HOME,                          // 0004 V3电机在原点. 1: 在原点; 0: 不在原点
    S1_AT_LIMIT,                         // 0005 S1电机在限位位置. 1: 在限位 0: 不在限位
    S2_AT_LIMIT,                         // 0006 S2电机在限位位置. 1: 在限位 0: 不在限位
    S1_AT_BUF,                           // 0007 S1电机在缓冲位置. 1: 在缓冲位 0: 不在缓冲位
    S2_AT_BUF,                           // 0008 S2电机在缓冲位置. 1: 在缓冲位 0: 不在缓冲位
    RACK_READY_IMPORTL,                  // 0009 左试管架推入到位, 1: 到位 0:未到位
    RACK_READY_IMPORTR,                  // 000A 右试管架推入到位, 1: 到位 0:未到位
    TUBE_EXIST,                          // 000B 样本管存在，1: 存在 0: 不存在.
    RACK_FIXED,                          // 000C 试管架到检测样本管位， 1: 到位 0:未到位
    RACK_READY_EXPORT,                   // 000D 试管架到轨道输出口位， 1: 到位 0:未到位
    STARTL_PRESSED,                      // 000E 左启动按钮按下, 1: 按下 0:未按下
    STARTR_PRESSED,                      // 000F 右启动按钮按下, 1: 按下 0:未按下
    STOP_PRESSED,                        // 0010 停止按钮按下, 1: 按下 0:未按下
    EXEC_CONDITIONS_ERROR,               // 0011 执行条件错误
    RACK_READY_IMPORTL_ERROR,            // 0012 未检测到轨道左输入区试管架到位 1: 未到位 0: 到位
    RACK_READY_IMPORTR_ERROR,            // 0013 未检测到轨道右输入区试管架到位 1: 未到位 0: 到位
    RACK_READY_EXPORT_ERROR,             // 0014 未检测到轨道输出口试管架到位 1: 未到位 0: 到位
    S1_HOME_SENSOR_ERROR,                // 0015 S1复位传感器故障. 1: 故障 0: 正常
    S2_HOME_SENSOR_ERROR,                // 0016 S2复位传感器故障. 1: 故障 0: 正常
    V1_HOME_SENSOR_ERROR,                // 0017 V1复位传感器故障. 1: 故障 0: 正常
    V2_HOME_SENSOR_ERROR,                // 0018 V2复位传感器故障. 1: 故障 0: 正常
    V3_HOME_SENSOR_ERROR,                // 0019 V3复位传感器故障. 1: 故障 0: 正常
    S1_LIMIT_SENSOR_ERROR,               // 001A S1限位传感器故障. 1: 故障 0: 正常
    S2_LIMIT_SENSOR_ERROR,               // 001B S2限位传感器故障. 1: 故障 0: 正常
    S1_MOTOR_ERROR,                      // 001C S1电机故障. 1: 故障 0: 正常
    S2_MOTOR_ERROR,                      // 001D S1电机故障. 1: 故障 0: 正常
    V1_MOTOR_ERROR,                      // 001E V1电机故障. 1: 故障 0: 正常
    V2_MOTOR_ERROR,                      // 001F V2电机故障. 1: 故障 0: 正常
    V3_MOTOR_ERROR,                      // 0020 V3电机故障. 1: 故障 0: 正常
    T1_MACHANSIM_ERROR,                  // 0021 T1传送机构故障. 1: 故障 0: 正常
    SCANNER_ERROR,                       // 0022 扫码器故障. 1: 故障 0: 正常
}RO_BIT_INDEX;

__packed typedef struct RO_BIT{
    uchar s1_at_home : 1;               // 0000 S1电机在原点. 1: 在原点 0: 不在原点
    uchar s2_at_home : 1;               // 0001 S2电机在原点. 1: 在原点 0: 不在原点
    uchar v1_at_home : 1;               // 0002 V1电机在原点. 1: 在原点; 0: 不在原点
    uchar v2_at_home : 1;               // 0003 V2电机在原点. 1: 在原点; 0: 不在原点
    uchar v3_at_home : 1;               // 0004 V3电机在原点. 1: 在原点; 0: 不在原点
    uchar s1_at_limit : 1;              // 0005 S1电机在限位位置. 1: 在限位 0: 不在限位
    uchar s2_at_limit : 1;              // 0006 S2电机在限位位置. 1: 在限位 0: 不在限位
    uchar rack_exist_prel : 1;          // 0007 试管架存在左预输入位, 1: 存在 0:不存在
    uchar rack_exist_prer: 1;           // 0008 试管架存在右预输入位, 1: 存在 0:不存在
    uchar rack_ready_importl : 1;       // 0009 左试管架推入到位, 1: 到位 0:未到位
    uchar rack_ready_importr : 1;       // 000A 右试管架推入到位, 1: 到位 0:未到位
    uchar tube_exist : 1;               // 000B 样本管存在，1: 存在 0: 不存在.
    uchar rack_fixed : 1;               // 000C 试管架到检测样本管位， 1: 到位 0:未到位
    uchar rack_ready_export : 1;        // 000D 试管架到轨道输出口位， 1: 到位 0:未到位
    uchar startl_pressed : 1;           // 000E 左启动按钮按下, 1: 按下 0:未按下
    uchar startr_pressed : 1;           // 000F 右启动按钮按下, 1: 按下 0:未按下
    uchar stop_pressed : 1;             // 0010 停止按钮按下, 1: 按下 0:未按下
    uchar exec_conditions_error : 1;    // 0011 执行条件错误
    uchar rack_ready_importl_error : 1; // 0012 未检测到轨道左输入区试管架到位 1: 未到位 0: 到位
    uchar rack_ready_importr_error : 1; // 0013 未检测到轨道右输入区试管架到位 1: 未到位 0: 到位
    uchar rack_ready_export_error : 1;  // 0014 未检测到轨道输出口试管架到位 1: 未到位 0: 到位
    uchar s1_home_sensor_error : 1;     // 0015 S1复位传感器故障. 1: 故障 0: 正常
    uchar s2_home_sensor_error : 1;     // 0016 S2复位传感器故障. 1: 故障 0: 正常
    uchar v1_home_sensor_error : 1;     // 0017 V1复位传感器故障. 1: 故障 0: 正常
    uchar v2_home_sensor_error : 1;     // 0018 V2复位传感器故障. 1: 故障 0: 正常
    uchar v3_home_sensor_error : 1;     // 0019 V3复位传感器故障. 1: 故障 0: 正常
    uchar s1_limit_sensor_error : 1;    // 001A S1限位传感器故障. 1: 故障 0: 正常
    uchar s2_limit_sensor_error : 1;    // 001B S2复位传感器故障. 1: 故障 0: 正常
    uchar s1_motor_error : 1;           // 001C S1电机故障. 1: 故障 0: 正常
    uchar s2_motor_error : 1;           // 001D S1电机故障. 1: 故障 0: 正常
    uchar v1_motor_error : 1;           // 001E V1电机故障. 1: 故障 0: 正常
    uchar v2_motor_error : 1;           // 001F V2电机故障. 1: 故障 0: 正常
    uchar v3_motor_error : 1;           // 0020 V3电机故障. 1: 故障 0: 正常
    uchar t1_machansim_error : 1;       // 0021 T1传送机构故障. 1: 故障 0: 正常
    uchar scanner_error : 1;            // 0022 扫码器故障. 1: 故障 0: 正常
    uchar basket_exist_prel : 1;        // 0023 左输入缓冲区试管架提篮存在, 1: 存在 0:不存在
    uchar basket_exist_prer : 1;        // 0024 右输入缓冲区试管架提篮存在, 1: 存在 0:不存在
    uchar hat_exist : 1;                // 0025 检测到试管架上样本管帽存在, 1: 存在 0:不存在
}RO_BIT;

extern  RO_BIT ro_bit;


#define RO_BIT_FIRST                        ((uchar*)&ro_bit)
#define RO_BIT_COUNT                        0x26

//------------------------------------------
// RW-BIT
//------------------------------------------

typedef struct RW_BIT{
    uchar start_scan : 1;               // 0000 启动停止条码扫描. 1:启动; 0:停止
    uchar export_stop_triggered : 1;    // 0001 检测到该值为1时停止trans_out，为0 时无效
    uchar start_l : 1;                  // 0002 启动左缓冲试管架队列推入. 1: 启动; 0: 停止
    uchar start_r : 1;                  // 0003 启动右缓冲试管架队列推入. 1: 启动; 0: 停止
    uchar beep_disable : 1;             // 0004 禁用蜂鸣器 1: 禁用; 0: 使能
    uchar key_long_pressed_l : 1;       // 0005 检测到按键长按置1，由软件清除
    uchar key_long_pressed_r : 1;       // 0006 检测到按键长按置1，由软件清除
    uchar disable_startl : 1;           // 0007 禁止或暂停按钮触发动作
    uchar disable_startr : 1;           // 0008 禁止或暂停按钮触发动作
}RW_BIT;

extern  RW_BIT rw_bit;

#define RW_BIT_FIRST        ((uchar*)&rw_bit)
#define RW_BIT_COUNT        9


typedef enum RO_LONG_ADD
{
    S1_POS_L = 0x3E,
    S1_POS_H,
    S2_POS_L,
    S2_POS_H,
    V1_POS_L,
    V1_POS_H ,
    V2_POS_L,
    V2_POS_H,
    V3_POS_L,
    V3_POS_H,
    T1_POS_L,
    T1_POS_H,
    S1_DISTANCE_L = 0x4B,
    S1_DISTANCE_H,
    S2_DISTANCE_L = 0x4E,
    S2_DISTANCE_H,
    V1_DISTANCE_L = 0x51,
    V1_DISTANCE_H ,
    V2_DISTANCE_L = 0x54,
    V2_DISTANCE_H,
    V3_DISTANCE_L = 0x57,
    V3_DISTANCE_H,
    T1_DISTANCE_L = 0x5A,
    T1_DISTANCE_H,

}RO_LONG_ADD;

extern RO_LONG_ADD ro_long_addL[12];
extern RO_LONG_ADD ro_long_addH[12];

#define RO_CHAR_COUNT   2

typedef struct RO_CHAR{
    ushort start;
    ushort end;
}RO_CHAR;

extern RO_CHAR rochar[RO_CHAR_COUNT];

//==========================================================
// RO-WORD
//==========================================================
__packed typedef struct RO_WORD{
      ushort server_status;               // 0000   服务器状态. 见 `SERVER STATUS`_.
      ushort rack_number;                 // 0001   上电以来,在扫码完成后轨道输出口,检测到试管架到位的数量
      ushort rack_flag;                   // 0002   若扫码完成轨道输出口存在试管架，该值表示试管架信息
                                          // | D15:5 保留,为0 | D4:0 表示当前样本架上对应的样本n存在
                                          //  - 对应位为1，存在
                                          //  - 对应位为0，不存在
      char barcodes[6][16];               // 0003/8 A1 样本条码
                                          // 000B/8 A2 样本条码
                                          // 0013/8 A3 样本条码
                                          // 001B/8 A4 样本条码
                                          // 0023/8 A5 样本条码
                                          // 002B/8 试管架条码
      char recent_barcode[16];           // 0033/8 最后扫到的条码
      ushort startl_pressed_duration;     // 003B   自左启动按钮按下以来经过的时间, ms
      ushort startr_pressed_duration;     // 003C   自右启动按钮按下以来经过的时间, ms
      ushort stop_pressed_duration;       // 003D   自停止按钮按下以来经过的时间, ms
      long pos[MACHINE_COUNT];
                                          // 003E/2 当前 S1方向电机 坐标,步
                                          // 0040/2 当前 S2方向电机 坐标,步
                                          // 0042/2 当前 V1方向电机 坐标,步
                                          // 0044/2 当前 V2方向电机 坐标,步
                                          // 0046/2 当前 V3方向电机 坐标,步
                                          // 0048/2 当前 T1方向电机 坐标, 步
      MACHINE_INFO mi[MACHINE_COUNT];
                                          // 004A   S1 运动经过的时间,ms
                                          // 004B/2 S1 运动经过的距离,步
                                          // 004D   S2 运动经过的时间,ms
                                          // 004E/2 S2 运动经过的距离,步
                                          // 0050   V1 运动经过的时间,ms
                                          // 0051/2 V1 运动经过的距离,步
                                          // 0053   V2 运动经过的时间,ms
                                          // 0054/2 V2 运动经过的距离,步
                                          // 0056   V3 运动经过的时间,ms
                                          // 0057/2 V3 运动经过的距离,步
                                          // 0059   T1 运动经过的时间,ms
                                          // 005A/2 T1 运动经过的距离,步
      char poscodes[5][8];                // 各样本位位置码。ASCII 字符串。每个条码占 4 条记录（8 字节），不足以 NUL(0) 结束。共 5 个条码。
      ushort rack_importl_refer_count;    // 记录的试管架状态，当transin动作时置状态为1，
                                          // 忽略传感器错误，正常动作退出 置1，
      ushort rack_importr_refer_count;
      ushort rack_export_refer_count;
      ushort barCount;                    // 扫到的条码数量
}RO_WORD;

extern RO_WORD ro_word;

#define RO_WORD_FIRST       ((ushort*)&ro_word.server_status)
#define RO_WORD_END         ((ushort*)&ro_word.z_distance - 1)
#define RO_WORD_COUNT       0x7D
#define RO_WORD_SIZE        (RO_WORD_END - RO_WORD_FIRST)

//==========================================================
// RW-WORD
//==========================================================

typedef enum RW_LONG_ADD
{
    S1_MAX_DISTANCE_L = 0x22,
    S1_MAX_DISTANCE_H,
    S2_MAX_DISTANCE_L = 0x25,
    S2_MAX_DISTANCE_H,
    V1_MAX_DISTANCE_L = 0x28,
    V1_MAX_DISTANCE_H ,
    V2_MAX_DISTANCE_L = 0x2B,
    V2_MAX_DISTANCE_H,
    V3_MAX_DISTANCE_L = 0x2E,
    V3_MAX_DISTANCE_H,
    T1_MAX_DISTANCE_L = 0x31,
    T1_MAX_DISTANCE_H,
}RW_LONG_ADD;

extern RW_LONG_ADD rw_long_addL[6];
extern RW_LONG_ADD rw_long_addH[6];

__packed typedef struct RW_WORD{
    ushort action;                  //  0000    当前执行指令
    ushort action_arg[16];          //  0001/16 ACTION参数
    APP_PARAM app_arg1;
    ushort app_args[15];
    MACHINE_PARAM mp[MACHINE_COUNT];//
    ushort s1_max_speed2;
    ushort s2_max_speed2;
    ushort t1_max_speed2;
    short v1_close_pos;
    short v2_close_pos;
    short v3_close_pos;
    LED_CNTRL led_cnt[2];
}RW_WORD;

extern RW_WORD rw_word;

#define RW_WORD_FIRST       ((ushort*)&rw_word.action)
#define RW_WORD_END         ((ushort*)&rw_word.temp_bias)
#define RW_WORD_COUNT       0x3A
#define RW_WORD_SIZE        (RW_WORD_END - RW_WORD_FIRST)


//------------------------------------------
// 文件
//------------------------------------------
#define FILE_COUNT              0
#define MAX_FILE_REQUEST        2       // 一次请求最大的子记录访问数量

//------------------------------------------
// 诊断
//------------------------------------------

#define PS_SENSOR_ERROR(n)                  (0x04 << (n))


extern ushort  diagnostic;
extern ushort  bus_message_count;
extern ushort  bus_error_count;
extern ushort  bus_exception_count;
extern ushort  server_message_count;
extern ushort  server_no_response_count;
extern ushort  server_exception_count;
extern ushort  server_busy_count;
extern ushort  bus_char_overrun_count;
extern ushort  server_status;
extern uchar   program_status;

extern bit ps_listen_only;                                        // 处于只听模式
extern bit ps_server_busy;                                        // 设备忙
extern bit ps_sensor_error_1;                                // 通道1温度传感器错误
extern bit ps_sensor_error_2;                                // 通道2温度传感器错误

// diagnostic寄存器位定义:


//------------------------------------------
// 事件
//------------------------------------------
#define MAX_EVENT_COUNT                                64                // 2^n
#define MAX_EVENT_MASK                                (MAX_EVENT_COUNT-1)

// 接收事件
#define EVENT_RECEIVED                                0x80        // 接收事件
#define EVENT_BROADCAST                               0x40        // 接收到广播消息
#define EVENT_LISTEN_ONLY                             0x20        // 当前处于只听模式
#define EVENT_CHARRACTER_OVERRUN                      0x10        // 字符过载
#define EVENT_COMMUNICATION_ERROR                     0x02        // 通讯错误

// 发送事件
#define EVENT_SENT                                    0x40        // 发送事件
//#define EVENT_LISTEN_ONLY                           0x20        // 当前处于只听模式
#define EVENT_WRITE_TIMEOUT                           0x10        // 写超时
#define EVENT_EXCEPTION                               0x80        // 异常应答
#define EVENT_BUSY_EXCEPTION                          0x04        // 错误代码 5-6
#define EVENT_ABORT_EXCEPTION                         0x02        // 错误代码 4
#define EVENT_READ_EXCEPTION                          0x01        // 错误代码 1-3

// 进入只听模式事件
#define EVENT_ENTER_LISTEN_ONLY                       0x04        // 进入只听模式事件

// 复位事件
#define EVENT_RESET_PORT                              0x00        // 复位事件

extern uchar event_count;                                        // 事件记数值, event_count索引的event_log为当前事件
extern uchar event_log[MAX_EVENT_COUNT];        // 事件记录

//------------------------------------------
// 异常应答代码
//------------------------------------------
#define ILLEGAL_FUNCTION                        0x01
#define ILLEGAL_DATA_ADDRESS                    0x02
#define ILLEGAL_DATA_VALUE                      0x03
#define SERVER_DEVICE_FAILURE                   0x04
#define ACKNOWLEDGE                             0x05
#define SERVER_DEVICE_BUSY                      0x06
#define MEMORY_PARITY_ERROR                     0x08
#define GATEWAY_PATH_UNAVAILABLE                0x0A
#define GATEWAY_TARGET_NO_RESPONSE              0x0B
#define ILLEGAL_DATA_COUNT                      0x0C
//----------------------------------------------------------------------------------
/*The bytes are coded in memory in Little Endian format.
    The lowest numbered byte in a word is considered the word’s
    least significant byte and the highest numbered byte the most significant.*/
//----------------------------------------------------------------------------------

ushort from_little_endian_16(ushort n);
ulong  from_little_endian_32(ulong n);



bit Uart0_FrameEnded(void);
void No_Response(void);
void Response(void);
void Exception_Response(uchar err);
void Process_Request(void);

uchar Read_RO_bit(ushort addr, uchar n);
uchar Read_RW_bit(ushort addr, uchar n);
//void Write_bit(ushort addr, uchar val);
void Write_RO_bit(ushort addr, uchar val, uchar n);
void Write_bit(ushort addr, uchar val, uchar n);
uchar Test_Bit(uchar *bits, ushort addr);
void Set_Bit(uchar *bits, ushort addr, bit val);
void Set_RO_Bit(ushort addr);
void Reset_RO_Bit(ushort addr);
ushort Read_RO_word(ushort addr);
ushort Read_RW_word(ushort addr);
void Write_word(ushort addr, ushort val);

uchar Read_Exception(void);
void Diagnose(void);
void Log_Event(uchar event);

void Read_Identification(void);

#if FILE_COUNT
// 文件操作
void Reset_File(uchar fid);
void Append_File(uchar fid, ushort *rec,ushort n);
//void Append_File(uchar fid, ushort rec);
void Append_File_Word(uchar fid, ushort rec);
ushort Read_File(uchar fid, ushort addr);
void Write_File(uchar fid, ushort addr, ushort val);
ushort File_Size(uchar fid);
void Set_File_Size(uchar fid, ushort size);
#endif//FILE_COUNT








#endif // MODBUS_H
